package test;

import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.regex.*;

public class strings
{
	/** übungen im umgang mit strings. **/
	public strings()
	{

	}

	/** Referenztypen sind neben den primitiven Datentypen die zweite wichtige Klasse von Datentypen in Java.
	 * Zu den Referenztypen gehören Objekte, Strings und Arrays.
	 * Weiterhin gibt es die vordefinierte Konstante null, die eine leere Referenz bezeichnet.
	 * 
	 * In Java ist eine Symbiose zwischen dem String als Objekt und dem String als eingebautem Datentyp vorgenommen worden.
	 * Die Sprache ermöglicht zwar die direkte Konstruktion von String-Objekten etwa aus String-Literalen
	 * (Zeichenketten in doppelten Anführungszeichen) und die Konkatenation (Aneinanderreihung von Strings mit +)
	 * von mehreren Strings, doch intern ist die Aneinanderreihung über Methoden der Klassen String,
	 * StringBuffer beziehungsweise StringBuilder realisiert.
	 * Mit dem Plus auf String-Objekten ist also ein besonderer Operator auf der Klasse String definiert,
	 * der nicht eigenständig auf anderen Klassen definiert werden kann.
	 * Java unterstützt keine überladenen Operatoren für Klassen, und dieses Plus ist ein Abweichler.
	 *
	 * In Java werden Strings als char-Arrays gespeichert.
	 * 
	 * sind quasi arrays welche nur zeichen d.h. buchstaben oder sonderzeichen als liste abspeichern.
	 * aus einem satz wird eine liste von buchstaben.
	 **/

	public static void main(String [] args)
	{
		/** string auf console ausgeben **/
		System.out.println("Hello World");
		
		/**
		* Die Zuweisung 
		**/
		String ref = "Hello World";
		// String ref = 'Hello World'; // '' einfache anführungszeichen markieren in java wohl keinen gültigen string, sehr kleinlich.
		String gef = ref; // creates an independent copy!
		System.out.println(gef); // original variable's content NOT changed.

		String Hello_World = "Hello World";
		/**
		"Hello_World"= "Hello World" (id=15)	
		CASE_INSENSITIVE_ORDER= String$CaseInsensitiveComparator  (id=32)	
		serialPersistentFields= ObjectStreamField[0]  (id=34)	
		serialVersionUID= -6849794470754667710	
		count= 11	
		hash= 0	
			'value' referenced from:	
			[0]= H	
			[1]= e	
			[2]= l	
			[3]= l	
			[4]= o	
			[5]=  	
			[6]= W	
			[7]= o	
			[8]= r	
			[9]= l	
			[10]= d	
		**/

		/** auf ein einzelnes zeichen dieses Zeichen-Arrays kann folgendermaßen zugegriffen werden **/
		char[] Hello_World_CharArray = "Hello World".toCharArray();
		System.out.println(Hello_World_CharArray[0]); // prints out H
		
		/**
		 * Überladene Methoden und variable Argumentlisten
		 */
		System.out.printf( "Hallo %s%n", "Welt" );               // Hallo Welt 
		System.out.printf( "%s ist %d Jahre alt%n", "Isy", 26 ); // Isy ist 26 Jahre alt

		/**
		 * 	Falls zusammenhängende Teile nicht alle den Datentyp String annehmen, werden sie automatisch in einen String umgewandelt.
		 */

		/**
			"Sandmännchen wünscht " + 12
			ergibt den einen String »Sandmännchen wünscht 12«.
	
			Besteht der Ausdruck aus mehreren Teilen, so muss die Auswertungsreihenfolge beachtet werden,
			andernfalls kommt es zu seltsamen Zusammensetzungen. So ergibt "Aufruf von " + 1 + 0 + 0 + " Ökonomen"
			tatsächlich »Aufruf von 100 Ökonomen« und nicht »Aufruf von 1 Ökonomen«,
			da der Compiler die Konvertierung in Strings dann startet,
			wenn der den Ausdruck als String-Objekt erkannt hat.
	
			Beispiel Auswertungsreihenfolge vom Plus:
			Listing 2.7    PlusString.java, main()
		 */

		System.out.println( 1 + 2 );       // 3 
		System.out.println( "1" + 2 );     // 12 
		System.out.println( 1 + "2" );     // 12 
		System.out.println( 1 + "2" + 3 ); // 123 
		System.out.println( "1" + 2 + 3 ); // 123 
		System.out.println( 1 + 2 + "3" ); // 33 
		System.out.println( '1' + 2 );     // 51 (ASCII-Wert von '1' ist 49) 
		System.out.println( 1 + '2' );     // 51

		/** Diese wurde in Java eingeführt, da ein Aneinanderhängen von Zeichenketten oft benötigt wird.
		 * Objekte vom Typ String können durch den Plus-Operator mit anderen Strings und Datentypen verbunden werden.
		 * Falls zusammenhängende Teile nicht alle den Datentyp String annehmen, werden sie automatisch in einen String umgewandelt.
		 * Der Ergebnistyp ist immer String.
		 */
//		Beispiel Setze fünf Teile zu einem String zusammen:
		String s = '"' + "Extrem Sandmännchen" + '"' + " frei ab " + 18; 
		//         char  String                  char  String        int 
		System.out.println( s ); // "Extrem Sandmännchen" frei ab 18

		/**	Besteht der Ausdruck aus mehreren Teilen, so muss die Auswertungsreihenfolge beachtet werden,
		 * andernfalls kommt es zu seltsamen Zusammensetzungen. So ergibt "Aufruf von " + 1 + 0 + 0 + " Ökonomen"
		 * tatsächlich »Aufruf von 100 Ökonomen« und nicht »Aufruf von 1 Ökonomen«,
		 * da der Compiler die Konvertierung in Strings dann startet,
		 * wenn er einen Ausdruck als String-Objekt erkannt hat.
		 **/

//		Beispiel Auswertungsreihenfolge vom Plus:
		System.out.println( 1 + 2 ); 				 // 3 
		System.out.println( "1" + 2 + 3 );			// 123 
		System.out.println( 1 + 2 + "3" );			// 33 
		System.out.println( 1 + 2 + "3" + 4 + 5 ); // 3345

		/** Beispiel Der Plus-Operator für Zeichenketten geht streng von links nach rechts und bereitet mit
		 * eingebetteten arithmetischen Ausdrücken mitunter Probleme. Eine Klammerung hilft,
		 * wie im Folgenden zu sehen ist:
		 */
		System.out.println( "Ist 1 größer als 2? " + (1 > 2 ? "ja" : "nein") );
		
		/** characters / chars
		 * sind variablen welche nur ein einziges zeichen buchstabe, zahl oder sonderzeichen speichern können.
		 * **/
		Character CHARACTER_1 = 'c';
		char CHARACTER = 'c';

		System.out.println( Character.isDigit( '0' ) );      // true 
		System.out.println( Character.isDigit( '-' ) );      // false 
		System.out.println( Character.isLetter( 'ß' ) );     // true 
		System.out.println( Character.isLetter( '0' ) );     // true 
		System.out.println( Character.isWhitespace( ' ' ) ); // true 
		System.out.println( Character.isWhitespace( '-' ) ); // false
		
	    /**
	     * Determines the character representation for a specific digit in
	     * the specified radix. If the value of <code>radix</code> is not a
	     * valid radix, or the value of <code>digit</code> is not a valid
	     * digit in the specified radix, the null character
	     * (<code>'&#92;u0000'</code>) is returned.
	     * <p>
	     * The <code>radix</code> argument is valid if it is greater than or
	     * equal to <code>MIN_RADIX</code> and less than or equal to
	     * <code>MAX_RADIX</code>. The <code>digit</code> argument is valid if
	     * <code>0&nbsp;&lt;=digit&nbsp;&lt;&nbsp;radix</code>.
	     * <p>
	     * If the digit is less than 10, then
	     * <code>'0'&nbsp;+ digit</code> is returned. Otherwise, the value
	     * <code>'a'&nbsp;+ digit&nbsp;-&nbsp;10</code> is returned.
	     *
	     * @param   digit   the number to convert to a character.
	     * @param   radix   the radix.
	     * @return  the <code>char</code> representation of the specified digit
	     *          in the specified radix.
	     * @see     java.lang.Character#MIN_RADIX
	     * @see     java.lang.Character#MAX_RADIX
	     * @see     java.lang.Character#digit(char, int)
	     */
		/** static char forDigit( int digit, int radix )
		 * Konvertiert einen numerischen Wert in ein Zeichen.
		 * Beispielsweise ist
		 * **/
		Character test = ' ';
		test = Character.forDigit(6, 8); //  gleich »6« und
		test = Character.forDigit(12, 16); // ist »c«.
		
		/** The count is the number of characters in the String. */
		Integer NUMBER = "Hi Chris".length(); // returns 8

		/**
			Diese wurde in Java eingeführt, da ein Aneinanderhängen von Zeichenketten oft benötigt wird. Objekte vom Typ String können durch den Plus-Operator mit anderen Strings und Datentypen verbunden werden. Falls zusammenhängende Teile nicht alle den Datentyp String annehmen, werden sie automatisch in einen String umgewandelt. Der Ergebnistyp ist immer String.
			Beispiel Setze fünf Teile zu einem String zusammen:
			String s = '"' + "Extrem Sandmännchen" + '"' + " frei ab " + 18; 
			//         char  String                  char  String        int 
			System.out.println( s ); // "Extrem Sandmännchen" frei ab 18
	
			Besteht der Ausdruck aus mehreren Teilen, so muss die Auswertungsreihenfolge beachtet werden, andernfalls kommt es zu seltsamen Zusammensetzungen. So ergibt "Aufruf von " + 1 + 0 + 0 + " Ökonomen" tatsächlich »Aufruf von 100 Ökonomen« und nicht »Aufruf von 1 Ökonomen«, da der Compiler die Konvertierung in Strings dann startet, wenn er einen Ausdruck als String-Objekt erkannt hat.
	
			Beispiel Auswertungsreihenfolge vom Plus:
			Listing 2.9 PlusString.java, main()
			System.out.println( 1 + 2 );               // 3 
			System.out.println( "1" + 2 + 3 );         // 123 
			System.out.println( 1 + 2 + "3" );         // 33 
			System.out.println( 1 + 2 + "3" + 4 + 5 ); // 3345
		**/
		
		/** converting shit back and forth **/
		/** string -> int **/
		int INT_1 = Integer.parseInt("123"); // not able to convert ascii-chars like a, b, c...
		String STRING_1 = "" + INT_1; // strange form of conversion but works

		double DOUBLE_1 = Double.parseDouble("123");
		
		/** How to extract Ascii codes from a String **/
		String Test = "ABCD";
		for(int i = 0; i < Test.length(); ++i )
		{
			char c = Test.charAt( i );
			int j = (int) c;
			System.out.println(j);
		}

		/** Um herauszufinden, ob der String keine Zeichen hat, lässt sich neben **/
		String STRING_3 = "";
		if(STRING_3.length() == 0)
		{
			/**	auch die Methode **/
			/** erst ab java 1.6 if(isEmpty(STRING_3)) **/
			System.out.println("this string is truly empty");
			/** nutzen **/
		}

		/** Die Objektmethode contains(CharSequence) testet, ob ein Teilstring (engl. substring)
		 * in der Zeichenkette vorkommt, und liefert true,
		 * wenn das der Fall ist.
		 * CharSequence ist unter anderem die gemeinsame Schnittstelle von String, StringBuffer und StringBuilder. **/
		STRING_3 = "Hello World";
		if(STRING_3.contains("Hello"))
		{
			System.out.println("this string contains the word Hello");
		}
		
		STRING_3 = "Hello";
		if(STRING_3.contains("H"))
		{
			System.out.println("this string contains the letter H");
		}

		/**
		 * Die Methode liefert die Fundstelle eines Zeichens beziehungsweise Teilstrings.
		 * Findet indexOf() nichts, liefert sie –1. **/
		String str = "Ernest Gräfenberg";

		int index = str.indexOf('e');                     // 3
		if(index != -1)
		{
			System.out.println("das zeichen e wurde im string "+str+" an der stelle gefunden "+index);
		}

		/**
		 * Die Belegung von index ist 3, da an der Position 3 das erste Mal ein »e« vorkommt.
		 **/
		/** der zweite parameter, gibt an ab welcher position im string mit der Suche begonnen werden soll.
		 * in diesem fall beginnt indexOf mit der suche, nach dem letzten fundort von 'e' um das nächste 'e' zu finden. **/
		index = str.indexOf( 'e', index+1 );              // 11
		if(index != -1)
		{
			System.out.println("Das zweite 'e' kann im string "+str+" an der stelle "+index+" gefunden werden.");
		}

		/** findet die erste und übernächste stelle an der das pattern 'es' vorkommt. **/
		String material = "In Deutschland gibt es immer noch ein Ruhrgebiet, " +
              "obwohl es diese Krankheit schon lange nicht mehr geben soll.";

		String pattern = "es";
		int erste = material.indexOf( pattern );       // 20
		int zweite = material.indexOf( pattern, material.indexOf(pattern) + 1 );       // 57
		System.out.println("Das pattern '"+pattern+"' wurde das erste mal an stelle "+erste+" und das zweite mal an stelle "+zweite+" gefunden." );

		/** Beispiel beschreibt das Zeichen c ein Escape-Zeichen,
		etwa einen Tabulator oder ein Return, dann soll die Bearbeitung weitergeführt werden. **/
		String c = "";
		if ( "\b\t\n\f\r\"\\".indexOf(c) >= 0 ) 
		{ 
			System.out.println("Sie haben Tab, return oder ein sonstiges Escape zeichen eingegeben." ); 
		}

		str = "Gary Schubach"; 
		index  = str.lastIndexOf( 'a' );                 // 10, von vorne aus gezählt kommt das letzte a an stelle 10 vor (nach dem 10ten buchstaben)
		System.out.println(index);
		/** Genauso wie bei indexOf() existiert eine überladene Version,
		die rückwärts ab einer bestimmten Stelle nach
		dem nächsten Vorkommen von »a« sucht. Wir schreiben: **/
		index = str.lastIndexOf( 'a', index - 1 );          // 1, das vorletzte a kommt nach dem ersten buchstaben, deswegen 1.
		System.out.println(index);

		/** Um Strings zu vergleichen, gibt es viele Möglichkeiten und Optionen.
		Zunächst sind da equals() für absolute Übereinstimmung
		Methode gibt true zurück, falls die Strings gleich lang sind und Zeichen für Zeichen übereinstimmen.
		Da in Java Strings auch als Objekte behandelt werden, ist ein vergleich von zwei Strings mit == nur dann war,
		wenn es sich wirklich um das gleiche Objekt handelt d.h. wenn beide Variablen Referenzen auf den gleichen Speicherpunkt
		sind wo das Objekt abgelegt ist. 
		**/
		
		STRING_1 = "gleich";
		String STRING_2 = new String("gleich");
		
		if((STRING_1 == STRING_2) == false)
		{
			System.out.println("Leider ist "+STRING_1+" nicht gleich "+STRING_2+" weil STRING_1 und STRING_2 an unterschiedlichen Orten gespeichert" +
					"sind d.h. voneinander unabhängige Kopien aber mit gleichem Inhalt sind" +
					"und der == vergleichs Operator sich nicht um den Inhalt kümmert, sondern ob es das gleiche Objekt ist.");
		}
		
		if(STRING_1.equals(STRING_2))
		{
			System.out.println("Jetzt ist "+STRING_1+" gleich "+STRING_2+" die STRING.equals(STRING2) Methode sich nicht " +
					"für den Speicherort des Objektes interessiert sondern nur für den Inhalt.");
		}
		
		STRING_1 = STRING_2;
		
		if((STRING_1 == STRING_2) == true)
		{
			System.out.println("Jetzt ist "+STRING_1+" gleich "+STRING_2+" weil STRING_1 und STRING_2 nur Links/Verknüpfungen auf den gleichen Speicher-Orten " +
			"sind d.h. wenn sich STRING_1 ändert, ändert sich auch STRING_2, die beiden Variablen sind nicht mehr unabhängige Kopien.");
		}

		/** equalsIgnoreCase() für einen Vergleich, der unabhängig von der Groß-/Kleinschreibung ist. **/
		str = "REISEPASS"; 
		boolean result1 = str.equals( "Reisepass" );             // false 
		boolean result2 = str.equalsIgnoreCase( "ReISePaSs" );   // true

		/** Nur ist der Rückgabewert von compareTo() kein boolean,
		sondern ein int. Das Ergebnis signalisiert, ob das Argument lexikografisch
		kleiner oder größer als das String-Objekt ist beziehungsweise mit diesem übereinstimmt.
		Das ist zum Beispiel in einer Sortierfunktion wichtig.
		Der Sortieralgorithmus muss beim Vergleich zweier Strings wissen,
		wie sie einzusortieren sind. **/

	    /**
	     * Compares two strings lexicographically.
	     * The comparison is based on the Unicode value of each character in
	     * the strings. The character sequence represented by this
	     * <code>String</code> object is compared lexicographically to the
	     * character sequence represented by the argument string. The result is
	     * a negative integer if this <code>String</code> object
	     * lexicographically precedes the argument string. The result is a
	     * positive integer if this <code>String</code> object lexicographically
	     * follows the argument string. The result is zero if the strings
	     * are equal; <code>compareTo</code> returns <code>0</code> exactly when
	     * the {@link #equals(Object)} method would return <code>true</code>.
	     * <p>
	     * This is the definition of lexicographic ordering. If two strings are
	     * different, then either they have different characters at some index
	     * that is a valid index for both strings, or their lengths are different,
	     * or both. If they have different characters at one or more index
	     * positions, let <i>k</i> be the smallest such index; then the string
	     * whose character at position <i>k</i> has the smaller value, as
	     * determined by using the &lt; operator, lexicographically precedes the
	     * other string. In this case, <code>compareTo</code> returns the
	     * difference of the two character values at position <code>k</code> in
	     * the two string -- that is, the value:
	     * <blockquote><pre>
	     * this.charAt(k)-anotherString.charAt(k)
	     * </pre></blockquote>
	     * If there is no index position at which they differ, then the shorter
	     * string lexicographically precedes the longer string. In this case,
	     * <code>compareTo</code> returns the difference of the lengths of the
	     * strings -- that is, the value:
	     * <blockquote><pre>
	     * this.length()-anotherString.length()
	     * </pre></blockquote>
	     *
	     * @param   anotherString   the <code>String</code> to be compared.
	     * @return  the value <code>0</code> if the argument string is equal to
	     *          this string; a value less than <code>0</code> if this string
	     *          is lexicographically less than the string argument; and a
	     *          value greater than <code>0</code> if this string is
	     *          lexicographically greater than the string argument.
	     */

		str = "A";
		if(str.compareTo( "A" ) == 0)
		{
			System.out.println("");
		}
		if(str.compareTo( "C" )	< 0)
		{
			System.out.println("");
		}
		if(str.compareTo( "X" ) > 0)
		{
			System.out.println("");
		}
		
		str = "Herbert";
		if(str.compareTo( "Haus" ) > 0)
		{
			System.out.println("\"Justus\" ist lexikografisch größer als \"Herbert\"");
		}
		if(str.compareTo( "Heinrich" ) == 0)
		{
		}
		if(str.compareTo( "Hüfer" )	< 0)
		{
			System.out.println("\"Hüfer\" ist lexikografisch kleiner als \"Herbert\"");
		}

		/** Ob ein String mit einem Wort beginnt oder endet, sagen startsWith() und endsWith(). **/
		/** Beispiel Die Methode endsWith() ist praktisch zum Testen von Dateinamenendungen,
		startsWith() für URL-Protokolle: **/
		String filename = "Echolallie.gif"; 
		boolean isGif   = filename.endsWith( ".gif" );                  // true 
		boolean isHttp  = "http://java-tutor.com".startsWith( "http" ); // true

		/** Zum Vergleichen von Teilen gibt es regionMatches(),
		eine Funktion, die auch unabhängig von der Groß-/Kleinschreibung arbeiten kann. **/

		/** Methode region-Matches(), mit der Teile einer Zeichenkette mit Teilen einer anderen verglichen werden können.

		In diesem Beispiel vergleicht regionMatches ob im STRING_1 nach dem 9ten Buchstaben 
		der Teil von STRING_2 gefunden werden kann, welcher beim 19ten Buchstaben von STRING_2
		beginnt und nach 6 Buchstaben aufhört. 
		Auf Deutsch: Die Methode versucht das Wort kinder aus STRING_2 in STRING_1 zu finden.
		Und zwar genau an der Stelle nach dem 9ten Buchstaben. Kompliziert? Isses auch. **/

		STRING_1 = "Deutsche KINDER sind zu dick"; 
		STRING_2 = "Bewegungsarmut bei KINDER";
		boolean BOOLEAN = STRING_1.regionMatches( 9, STRING_2, 19, 6 );

		/** Sollte der Vergleich unabhängig von der Groß-/Kleinschreibung stattfinden,
		ist das erste Argument der überladenen Funktion true: **/
		BOOLEAN = STRING_1.regionMatches( true, 9, STRING_2, 19, 6 );

		/**
		Beispiel Liefere das erste und letzte Zeichen im String s:
		String s = "Ich bin nicht dick! Ich habe nur weiche Formen.";
		**/
		char first = STRING_1.charAt( 0 );                          // 'D'
		System.out.println(first);
		String FIRST = STRING_1.substring(0,1);                     // 'D'
		System.out.println(FIRST);
		char last  = STRING_1.charAt( STRING_1.length() - 1 );             // 'k'
		System.out.println(last);

		/** Beispiel substring(int) liefert eine Teilzeichenkette
		 * ab einem Index bis zum Ende.
		 * Das Ergebnis ist ein neues String-Objekt.
		 * **/
		STRING_1 = "SO EIN SCHMARREN"; 
		System.out.println(STRING_1.substring( 7 )); // SCHMARREN von zeichen 7 bis ende... 
		System.out.println(STRING_1.substring( 0,2 )); // SO von zeichen 0 bis 2

		/**
		 * Beispiel Kopiere Teile des Strings in ein Feld:
		**/
		STRING_1 = "Blasiussegen";
		char[] chars = new char[ 5 ]; 
		int srcBegin = 7;
		STRING_1.getChars(    srcBegin, STRING_1.length(),      chars,           0 );
		//       getChars(int srcBegin, int srcEnd       , char dst[], int dstBegin) {
		System.out.println( new String(chars) );  // segen
		/**
		 * @param      srcBegin   index of the first character in the string
	     *                        to copy.
	     * @param      srcEnd     index after the last character in the string
	     *                        to copy.
	     * @param      dst        the destination array.
	     * @param      dstBegin   the start offset in the destination array.

		 * kopiert ab Position 7 aus dem String STRING_1 5 Zeichen in die Elemente des Arrays chars.
		 * Das erste Zeichen aus dem Ausschnitt steht dann in chars[0].
		 **/

		/** Möchten wir den kompletten Inhalt eines Strings als ein Array von Zeichen haben, so können wir die Methode toCharArray() verwenden.
		Intern arbeitet die Methode auch mit getChars(). Als Ziel-Array legt toCharArray() nur ein neues Array an, das wir dann zurückbekommen.
		Beispiel Die untersten vier Bits von i sind in eine hexadezimale Ziffer umzuwandeln:
		**/
		char CHAR_A = "0123456789ABCDEF".toCharArray()[10];
		System.out.println( CHAR_A );
		/**
		Für diesen speziellen Fall wäre charAt() zwar schneller gewesen, doch demonstriert das Beispiel, dass wir per [] auch direkt auf die Array-Elemente eines Methodenergebnisses zugreifen können. Das ist völlig korrekt, denn toCharArray() liefert ein Array als Ergebnis.
		Auf Deutsch: Aus dem String "0123456789ABCDEF" wird ein CHAR-Array gemacht und anschließend auf deses zugegriffen.
		**/
		

		/**
		Eine weitere Methode erlaubt das Anhängen von Teilen an einen String. Wir haben dies schon öfters mit dem Plus-Operator realisiert. Die Methode von String dazu heißt concat(String). Wir werden später sehen, dass es die StringBuffer/StringBuilder-Klassen noch weiter treiben und eine überladene Methode append() mit der gleichen Funktionalität anbieten. Das steckt auch hinter dem Plus-Operator. Der Compiler wandelt dies automatisch in eine Kette von append()-Aufrufen um.
		Beispiel Hänge das aktuelle Tagesdatum hinter eine Zeichenkette:
		**/
		String s1 = "Das aktuelle Datum ist: "; 
		String s2 = new Date().toString(); 
		String s3 = s1.concat( s2 ); // Das aktuelle Datum ist: Tue Jun 05 14:46:41 CEST 2005
		
		System.out.println("1 und".concat(" 2 und".concat(" 3 und".concat(" 4 "))));

		System.out.println("1 und"+" 2 und"+" 3 und"+" 4 "); // essentially the same, but little slower.
		
		/**
		Die concat()-Methode arbeitet relativ zügig und effizienter als der Plus-Operator, der einen temporären String-Puffer anlegt. Doch mit dem Plus-Operator ist es hübscher anzusehen. (Aber wie das so ist: Sieht nett aus, aber ...)
		**/		

		/**
		Beispiel Konvertierung von Groß- in Kleinbuchstaben und umgekehrt:
		**/
		s1 = "Spaß in der Naßzelle."; 
		s2 = s1.toUpperCase();      // SPASS IN DER NASSZELLE. 
		System.out.println( s2 ); //
		System.out.println( s2.length() - s1.length() ); // -> differenz zwischen s1 und s2 beträgt 2, warum? weil beide ß zu SS werden, Das Beispiel dient zugleich als Warnung, dass sich im Fall von »ß« die Länge der Zeichenkette vergrößert.
		
		s1 = "Spaß in der Naßzelle.";
		s1 = s1.toLowerCase(Locale.getDefault());      // spass in der naßzelle. das gleiche passiert bei SS -lowercase-> ß
		System.out.println( s1 ); //

		/** Um länderspezifische Besonderheiten zu berücksichtigen, lassen sich die toXXXCase()-Methoden zusätzlich
		 * mit einem Locale-Objekt füttern. (Wir gehen im Kapitel 10 auf Sprachumgebungen und die Klasse Locale ein.) Die parameterlosen Methoden
		 * wählen die Sprachumgebung gemäß den Länder-Einstellungen des Betriebssystems: **/
		s1 = s1.toLowerCase(Locale.CHINESE);      // in chinese does not change anything.
		System.out.println( s1 ); //
		
		s1 = "\t bla und noch ein leerzeichen         yeah yeah yeah \n\t";
		s1 = s1.trim(); /** löscht sämmtlichen white-space vom ANFANG und ENDE eines strings
		Texts Leerraum wie Leerzeichen oder Tabulatoren. Vor der Bearbeitung sollten sie entfernt werden. Die String-Klasse bietet dazu trim() an. Diese Methode entfernt Leer- und ähnliche Füllzeichen am Anfang und Ende eines Strings
		**/
		
		/** suchen & ersetzten **/

		s1 = "apfel muß!";
		s1 = s1.replace('a', 'b'); // -> bpfel muß! replace(char oldChar, char newChar). Ersetzt einzelne Zeichen.
		System.out.println(s1);
		/**
		 * Gibt es etwas zu ersetzen, erzeugt replace() intern ein neues Zeichenfeld, führt die Ersetzungen durch und konvertiert das interne Zeichenfeld in ein String-Objekt, was die Rückgabe ist. Gab es nichts zu ersetzen, bekommen wir das gleiche String-Objekt zurück, das die Anfrage stellte.
		 */
		s1 = s1.replace("bpfel", "erdbeer"); // -> erdbeer muß! replace( CharSequence target, CharSequence replacement). Ersetzt eine Zeichenkette durch einen andere Zeichenkette.
		System.out.println(s1);
		s1 = "Schnecken erschrecken, wenn Schnecken an Schnecken schlecken, " + 
		           "weil zum Schrecken vieler Schnecken, Schnecken nicht schmecken."; 
		System.out.println( s1.replace("Schnecke", "Katze") );
		// Das Ergebnis auf dem Bildschirm ist »Katzen erschrecken, wenn Katzen an Katzen schlecken, weil zum Schrecken vieler Katzen, Katzen nicht schmecken.«

		// s1.replaceAll(regex, replacement) // replaceAll( String regex, String replacement). Ersetzt alle Strings, die durch einen regulären Ausdruck beschrieben werden.
		 // replaceFirst( String regex, String replacement). Ersetzt den ersten String, der durch einen regulären Ausdruck beschrieben wird.
		
		/** Die Funktionen replaceAll() und replaceFirst() suchen in Zeichenketten mit Hilfe von regulären Ausdrücken und nehmen Ersetzungen vor;
		 * replaceFirst() ersetzt, wie der Name schon sagt, nur das erste Auftreten.Für ganz allgemeine Ersetzungsaufgaben mit beliebigen Zeichen
		 * eignen sich replaceAll() und replaceFirst() nicht; hier ist die replace()-Funktion passend. Denn da der Suchstring immer ein regulärer
		 * Ausdruck ist, können Sonderzeichen auftauchen, die eine besondere Rolle spielen. So müssen zum Beispiel Dollar oder Punkt mit »\« ausmaskiert werden.
		 */

		// Beispiel Für eine String-Ersetzung stellen wir replace() und replaceAll() nebeneinander:
		s1 = "'Tag, Karl.''Wie geht's,Karl?''Gut, Karl.''Kahl, Karl?''Ja, Karl, ganz kahl.'"; 
		System.out.println( s1.replace(".", "!") ); // s1 = "'Tag, Karl!''Wie geht's,Karl?''Gut, Karl!''Kahl, Karl?''Ja, Karl, ganz kahl!'";

		s1 = "'Tag, Karl.''Wie geht's,Karl?''Gut, Karl.''Kahl, Karl?''Ja, Karl, ganz kahl.'"; 
		System.out.println( s1.replaceAll("\\.", "!") ); // s1 = "'Tag, Karl!''Wie geht's,Karl?''Gut, Karl!''Kahl, Karl?''Ja, Karl, ganz kahl!'";
		/** Der Punkt steht in regulären Ausdrücken für beliebige Zeichen.
		 * Erst, wenn dieser mit \\ ausmaskiert wird, liefert die Anweisung wie in s.replaceAll("\\.", "!") 
		 * das gewünschte Ergebnis. Die statische Methode quote()
		 * aus der Klasse String nimmt für uns die Ersetzungen vor.
		 * Wegen dem Sonderstatus vom »\« muss auch dieses Zeichen selbst ausmaskiert werden.
		 **/

		// Hier ersetzen wir alle Punkte durch Ausrufezeichen, sodass das Ergebnis wie folgt lautet:
		// s1.replaceAll(".", "!"); führt das nicht zum Erfolg, sondern nur zu der Zeichenkette:
		System.out.println( s1.replaceAll(".", "!") );	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		
		/** Beispiel Erzeuge aus einem char-Feld mit Vokalen ein String-Objekt. **/
		char[] vocalsArray = { 'a', 'e', 'i', 'o', 'u' }; 
		String vocal = new String( vocalsArray );

		/** decypher csv and put key=values into a HashMap **/
    	String data_format = "csv"; // csv
    	String first_line_contains_keys = "yes"; // true or false
    	String value_enclosed_by = "\"";
    	String values_delimiter = ",";
    	String line_delimiter = ";";
    	String data = "\"Erfasst am Datum\",\"Nr.\",\"Handelsvertreter\",\"Maschinenring\",\"Kunde\",\"Ort\",\"Tel. /e-mail\",\" Netto - € \",\"kWp \",\"VC %\",\"Bemerkungen\",\"Priorität\",\"Hoch\";,1514,\"Michael Huste\",,\"Kieser\",\"86441 Zusmarshausen\",\"08291-18087\",\"333.710,09 €\",\"115,38\",\"10,00%\",\" wartet Angebot Dachdecker ab,; leider tel. noch nicht erreicht\",,;09.10.09,1863,\"Michael Huste\",,\"Pagel\",\"86513 Ursberg\",\"08281-999751\",\"39.186,29 €\",\"15,12\",\"10,00%\",\"wartet noch auf pläne vom ;architekt zum bau des carports. \",,;16.10.09,1903,\"Michael Huste\",\"MR\",\"Engelhart Martin\",\"89365 Rosshaupten\",\"08222-2510\",\"69.107,82 €\",\"25,2\",\"10,00%\",\"wartet auf LEW wg. einspeisung;\",,;19.10.09,1927,\"Michael Huste\",,\"Leybrand\",\"89359 Großkötz\",\"0160-96991000\",\"32.542,56 €\",\"10,8\",\"80,00%\",\"wird sich die nä. 3 tage bei uns melden, sieht gut aus für Unterschrift\",,;10.12.09,2179,\"Michael Huste\",,\"Müller a\",\"86368 Gersthofen\",\"0172-9648781\",\"21.331,84 €\",\"8,1\",\"50,00%\",\" ;wartet noch auf Dachdecker\",,;07.01.10,2283,\"Michael Huste\",\"MR\",\"Dir\",\"89346 Anhofen\",\"0170-7618742\",\"368.417,00 €\",\"144,18\",\"50,00%\",\"HV vereinbart Termin zur nochmaligen Beratung in KW13;kunde schaut gerade nach finanzierung\",,;25.01.10,2406,\"Michael Huste\",\"MR\",\"Enderle\",\"89073 Ulm\",1774061983,\"31.894,00 €\",\"12,06\",\"20,00%\",\"will aktuelle preise,;ich warte noch auf überarbeitetes angebot mit neuen preisen\",,;25.01.10,2408,\"Michael Huste\",,\"Bertele\",\"89284 Pfaffenhofen\",1733427794,\"130.678,00 €\",\"51,12\",\"10,00%\",\"ca. 1km zum Trafo er überlegt jetzt ob er uns Auftrag geben will, ;damit wir mit LEW in verbindung treten können, (hab ihm Blanko Vertrag gemailt)\",,;25.01.10,2440,\"Michael Huste\",,\"Jehle\",\"73342 gosbach\",73356475,\"21.344,00 €\",\"7,92\",\"10,00%\",\"Kunde hatte Schlaganfall, überlegt ;jetzt ob er Anlage noch möchte\",,;28.01.10,2493,\"Michael Huste\",,\"Heinz\",\"86441 Zusmarshausen\",82918110,\"45.700,00 €\",\"18,36\",\"30,00%\",\"hat sich noch nicht entschieden, ;möchte sich demnächst entscheiden\",,;09.03.10,2951,\"Michael Huste\",\"MR\",\"Blaschke\",\"89233 Neu-Ulm\",731715368,\"74.000,00 €\",\"28,08\",\"60,00%\",\"möchte moch auf einspeisezusage warten, ca. 1 woche\",,;12.03.10,3034,\"Michael Huste\",,\"Heiligmann\",\"89368 Winterbach\",,\"93.000,00 €\",\"35,28\",\"30,00%\",\"Kunde wartet auf genehmigung vom Bauamt GZ\",,;12.03.10,3036,\"Michael Huste\",\"MR\",\"Strehle\",\"89368 Winterbach\",9075701603,\"85.000,00 €\",\"32,4\",\"60,00%\",\"Kunde benötigt ca. 1 Woche zum überlegen\",,;22.03.10,3135,\"Michael Huste\",,\"Imbiel\",\"89367 Waldstetten\",\"08223-2510\",\"27.812,98 €\",\"9,72\",\"30,00%\",\"ist noch nicht zur durchsicht gekommen\",,;31.03.10,3237,\"Michael Huste\",,\"Binder\",\"89231 Neu-Ulm\",\"0172-7120664\",\"131.223,74 €\",\"50,4\",\"20,00%\",\"Halle ist noch in Planung\",,;07.04.10,3257,\"Michael Huste\",,\"Schneider\",\"89223 Pfuhl\",\"0731-9717117\",\"19.791,19 €\",\"6,84\",\"10,00%\",\"vermutlich kein interesse mehr\",,;12.04.10,3312,\"Michael Huste\",,\"Rommer\",\"89438 Holzheim\",\"09075-238\",\"25.504,26 €\",\"9,72\",\"30,00%\",\"Kunde ist im Urlaub\",,;12.04.10,,\"Michael Huste\",,\"Neher\",\"89415 Lauingen\",\"0174-8324596\",,,\"40,00%\",\"Angebot abgegeben\",,;12.04.10,3314,\"Michael Huste\",\"MR\",\"Wuchenauer\",\"89215 Thalfingen\",\"0731-264602\",\"61.818,70 €\",\"23,76\",\"60,00%\",\"kunde benötigt ca. 2 Wochen zum überlegen\",,;14.04.10,3383,\"Michael Huste\",,\"Schalk\",\"89346 Bühl\",\"08226-868415\",\"79.248,98 €\",\"29,88\",\"40,00%\",\"Angebot abgegeben\",,;16.04.10,,\"Michael Huste\",,\"Kersten 2\",\"89343 Jettingen-Scheppach\",\"0172-8274740\",,,\"60,00%\",\"Angebot abgegeben\",,;19.04.10,3402,\"Michael Huste\",\"MR\",\"Biener\",\"89359 Kötz Ebersbach\",\"08223-2465\",\"117.929,69 €\",\"31,68\",\"70,00%\",\"Angebot abgegeben\",,;23.04.10,3446,\"Michael Huste\",,\"Eberle\",\"89346 Anhofen\",\"08226-635\",\"137.439,10 €\",\"54,72\",\"60,00%\",\"Abgabe auf der Leistungsschau\",,;23.04.10,3426,\"Michael Huste\",,\"Häußle\",\"89129 Hörvelsingen\",\"0731-2056176\",\"13.508,53 €\",\"4,1\",,\"Angebot abgegeben\",,;23.04.10,3429,\"Michael Huste\",,\"Lemke\",\"89335 Ichenhausen\",\"0173-3654373\",\"48.899,33 €\",\"19,62\",50,\"Angebot abgegeben\",,;23.04.10,3435,\"Michael Huste\",,\"Schneider\",\"89584 Granheim\",\"0152-06028984\",\"108.040,79 €\",\"42,12\",,\"Angebot abgegeben\",,;27.04.10,3459,\"Michael Huste\",\"MR\",\"Knaier Johannes\",\"89346 Silheim\",\"08226-868797\",\"75.826,61 €\",\"29,88\",,\"Angebot abgegeben\",,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;,,\"Michael Huste\",,,,,,,,,,;";;
		
    	String[] KEYS = null;
    	String[] VALUES = null;
    	HashMap hashMap = new HashMap();
    	Integer counter=0;
    	Integer KEY_COUNT = 0;
    	String VALUE = "";
    	String KEY = "";
    	
    	Pattern PATTERN1 = Pattern.compile(line_delimiter);
    	Pattern PATTERN2 = Pattern.compile(values_delimiter);

    	/** Split a String into a Java Array of Strings divided by an RE
		 */
    	// split by line
	    String[] LINES = PATTERN1.split(data);
	    for (counter=0; counter<LINES.length; counter++)
	    {
	    	// split by values
	    	if(first_line_contains_keys.equals("yes"))
	    	{
	    		// first line contains keys
	    		if(counter == 0)
	    		{
	    			KEYS = PATTERN2.split(LINES[counter]);
	    		}
	    		else
	    		{
	    			VALUES = PATTERN2.split(LINES[counter]);
	    		    // removing value_enclosed_by
	    		    for (counter=0; counter<VALUES.length; counter++)
	    		    {
	    		    	VALUE = VALUES[counter];
	    		    	VALUE = VALUE.replace(value_enclosed_by, "");
	    		    	KEY = KEYS[KEY_COUNT];
	    		    	KEY = KEY.replace(value_enclosed_by, "");
	    		    	hashMap.put(KEY, VALUE);
	    		    	KEY_COUNT++;
	    		    	if(KEYS.length <= KEY_COUNT)
	    		    	{
	    		    		KEY_COUNT = 0;
	    		    	}
	    		    }
	    		}
	    	}
	    }
	}
}